package com.irdstudio.apicenter.gateway.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

import com.irdstudio.apicenter.gateway.core.dm.AppChannelForward;

/**
 * Socket通讯工具类
 */
public class SocketUtil {

	/**
	 * 与远端服务器交换数据（没有长度标示，发完为止，收完为止）
	 * 
	 * @param sIp
	 *            主机名
	 * @param nPort
	 *            主机监听端口
	 * @param byData
	 *            发送数据
	 * @param nTimeOut
	 *            超时设置(毫秒级)
	 * @return 返回数据
	 */
	public static byte[] exchange(String sIp, int nPort, byte[] byData,
			int nTimeOut) throws IOException {
		Socket sock = new Socket(sIp, nPort);
		byte[] byRecv;
		try {
			sock.setSoTimeout(nTimeOut);
			BufferedInputStream in = new BufferedInputStream(
					sock.getInputStream());
			DataOutputStream out = new DataOutputStream(
					new BufferedOutputStream(sock.getOutputStream()));

			out.write(byData, 0, byData.length);
			out.flush();

			byRecv = readStream(in);
			in.close();
			out.close();
		} finally {
			sock.close();
		}

		return byRecv;
	}

	/**
	 * 从缓冲输入流中读取数据流，直到没有数据为止，可用于没有长度表示的套接数据接收
	 * 
	 * @param stream
	 *            缓冲输入流
	 * @return 数据流
	 */
	public static byte[] readStream(InputStream stream) throws IOException {
		// 返回字节流
		byte[] byRet = new byte[0];
		// 套接字输入流
		InputStream in;
		if (stream instanceof BufferedInputStream) {
			in = stream;
		} else {
			in = new BufferedInputStream(stream);
		}
		byte[] byRead = new byte[8192];
		int nRead = 0;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try {
			while ((nRead = in.read(byRead)) > 0) {
				if (nRead < 8192 || in.available() == 0) {
					baos.write(byRead, 0, nRead);
					break;
				}
				baos.write(byRead);
			}
		} catch (EOFException e) {
			e.printStackTrace();
		} catch (IOException e) {
			throw e;
		}
		byRet = baos.toByteArray();
		if (nRead < 0 && byRet.length == 0)
			throw new IOException("对方连接已关闭");
		return byRet;
	}

	/**
	 * 从缓冲输入流中读取数据流，读取指定长度字符报文
	 * 
	 * @param in
	 * @param acf
	 * @return
	 * @throws IOException
	 */
	public static byte[] readPackage(InputStream in, AppChannelForward acf)
			throws IOException {
		int PKG_LENGTH_HEADLEN = 6;// 获取报文前6个字符，表示报文长度
		String charsetName = acf.getChannelCharset();// 字符编码
		byte[] lenHeadBuf = new byte[PKG_LENGTH_HEADLEN];
		int off = 0;
		// 获得包头
		while (off < PKG_LENGTH_HEADLEN) {
			off = off + in.read(lenHeadBuf, off, PKG_LENGTH_HEADLEN - off);
			if (off < 0) {
				throw new IOException("Socket was closed! while reading...");
			}
		}
		int contentLength = Integer
				.parseInt(new String(lenHeadBuf, charsetName));
		byte[] Buf = new byte[contentLength];// 用于接收报文体
		off = 0;

		int n = 0;// 记录已接收长度
		while (off >= 0) {

			off = in.read();
			if (n >= 0) {
				Buf[n] = (byte) off;
				n++;
			}
			if (off == 0 || n >= contentLength) {
				break;
			}
		}

		if (n <= 0) {
			throw new IOException("返回报文为空");
		}
		// System.err.println("r>>>" + new String(Buf,PKG_ENCODE));

		System.out.println("最终收到 的报文:" + contentLength
				+ new String(Buf, charsetName));
		String st_buf = new String(Buf, charsetName);
		return st_buf.getBytes(charsetName);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

	}

}
